package com.xgs.web.controller.system;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xgs.common.annotation.Log;
import com.xgs.common.core.controller.BaseController;
import com.xgs.common.core.domain.AjaxResult;
import com.xgs.common.core.domain.entity.SysUser;
import com.xgs.common.core.page.TableDataInfo;
import com.xgs.common.enums.BusinessType;
import com.xgs.common.utils.DateUtils;
import com.xgs.common.utils.DictUtils;
import com.xgs.common.utils.StringUtils;
import com.xgs.common.utils.poi.ExcelUtil;
import com.xgs.common.utils.sign.Md5Utils;
import com.xgs.common.utils.uuid.IdUtils;
import com.xgs.system.domain.*;
import com.xgs.system.domain.vo.CompositeKey;
import com.xgs.system.service.*;
import com.xgs.web.dto.RosterDto;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDate;
import java.time.Month;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * @author JerryLu
 * @date 2024/10/23 11:05
 * @description 基础版本信息数据Controller
 */
@RestController
@RequestMapping("/system/basic_version")
@Slf4j
public class BasicVersionController extends BaseController {
    private static final Map<String, Object> res = new HashMap<>();
    private static final Map<String, Object> queryRes = new HashMap<>();
    @Autowired
    private BasicVersionService versionService;
    @Autowired
    private RosterService rosterService;
    @Autowired
    private RosterHistoryService historyService;
    @Autowired
    private LaneService laneService;
    @Autowired
    private FeeService feeService;

    /**
     * 查询收费站信息数据列表
     */
    @PreAuthorize("@ss.hasPermi('system:basic_version:list')")
    @GetMapping("/list")
    public TableDataInfo list(BasicVersion version) {
        startPage();
        if (!SysUser.isAdmin(getUserId())) {
            version.setDeptId(getDeptId());
        }
        List<BasicVersion> list = versionService.queryList(version);
        return getDataTable(list);
    }

    /**
     * 新增收费站信息数据
     */
    @PreAuthorize("@ss.hasPermi('system:basic_version:add')")
    @Log(title = "基础版本信息", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody BasicVersion version) {
        version.setId(IdUtils.fastSimpleUUID());
        version.setOperatorId(StringUtils.isNotEmpty(version.getOperatorId()) ? version.getOperatorId() : getUsername() + "_" + getDeptId());
        version.setOperatorName(StringUtils.isNotEmpty(version.getOperatorName()) ? version.getOperatorName() : getLoginUser().getUser().getNickName());
        version.setDeptId(getDeptId());
        version.setCreateTime(DateUtils.getNowDate());
        return toAjax(versionService.save(version));
    }

    /**
     * 打包
     */
    @PreAuthorize("@ss.hasPermi('system:basic_version:pack')")
    @Log(title = "基础版本信息", businessType = BusinessType.PACK)
    @PostMapping("/pack")
    @Transactional
    public AjaxResult pack(@RequestBody BasicVersion version) {
        try {
            QueryWrapper<Roster> query = Wrappers.query();
            query.eq("basic_id", version.getId());
            List<Roster> list = rosterService.list(query);
            if (list.isEmpty()) {
                return AjaxResult.error(-1, "不能打包空记录，请添加！");
            }
            String ver = DateUtils.dateTimeNow();
            version.setUpdateTime(DateUtils.getNowDate());
            version.setVersion(ver);
            version.setState(1);
            boolean res = true;
            boolean re = versionService.updateById(version);
            for (Roster roster : list) {
                RosterHistory history = JSON.parseObject(JSON.toJSONString(roster), RosterHistory.class);
                history.setId(IdUtils.fastSimpleUUID());
                history.setVersion(ver);
                history.setCreateTime(DateUtils.getNowDate());
                history.setDeptId(getDeptId());
                history.setSpare3(0);
                res = historyService.save(history);
            }
            if (!res) {
                return AjaxResult.error(-1, "打包失败");
            }
            return success(ver);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return error();
    }

    /**
     * 名单下发
     */
    @PreAuthorize("@ss.hasPermi('system:basic_version:issued')")
    @Log(title = "基础版本信息", businessType = BusinessType.ISSUED)
    @PostMapping("/issued")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult issued(@RequestBody BasicVersion basicVersion) {
        String ver = basicVersion.getVersion();
        QueryWrapper<RosterHistory> query = Wrappers.query();
        query.le("version", ver);
        query.in("spare3", 0, 3, 4);
        query.eq("dept_id", getDeptId());
        query.eq("del_flag", 0);
        query.apply("end_date >= TO_TIMESTAMP({0}, 'YYYY-MM-DD HH24:MI:SS')", DateUtils.getTime());
        List<RosterHistory> list = historyService.list(query);
        Map<String, List<RosterHistory>> groupedByStation = list.stream().collect(Collectors.groupingBy(RosterHistory::getExStationId));

        // 使用异步处理
        List<CompletableFuture<Void>> futures = new ArrayList<>();
        for (Map.Entry<String, List<RosterHistory>> entry : groupedByStation.entrySet()) {
            String stationId = entry.getKey();
            List<RosterHistory> dataModels = entry.getValue();
            futures.add(sendPostRequestAsync(basicVersion, stationId, dataModels));
        }

        // 等待所有异步任务完成，并检查是否有失败的任务
        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
        // 检查是否有任何任务失败
        boolean allSuccessful = futures.stream().allMatch(CompletableFuture::isDone);

        if (allSuccessful) {
            updateBasicVersionState(basicVersion);
            deleteRosterData(basicVersion.getId());
            return toAjax(1);
        } else {
            return AjaxResult.error(-1, "部分下发失败，请联系管理员");
        }


//        groupedByStation.forEach((stationId, dataModels) -> sendPostRequest(basicVersion, stationId, dataModels));
//        if (res.get("code") == "ok") {
//            BasicVersion basic = new BasicVersion();
//            basic.setId(basicVersion.getId());
//            basic.setState(3);
//            basic.setUpdateTime(DateUtils.getNowDate());
//            versionService.updateById(basic);
//
//            //删除下发表数据
//            Map<String, Object> columnMap = new HashMap<>();
//            columnMap.put("basic_id", basicVersion.getId());
//            rosterService.removeByMap(columnMap);
//            return toAjax(1);
//        } else {
//            return AjaxResult.error(-1, res.get("msg").toString());
//        }
    }

    // 更新基本版本状态的方法
    private void updateBasicVersionState(BasicVersion basicVersion) {
        BasicVersion basic = new BasicVersion();
        basic.setId(basicVersion.getId());
        basic.setState(3);
        basic.setUpdateTime(DateUtils.getNowDate());
        versionService.updateById(basic);
    }

    // 删除名单表数据的方法
    private void deleteRosterData(String basicVersionId) {
        Map<String, Object> columnMap = new HashMap<>();
        columnMap.put("basic_id", basicVersionId);
        rosterService.removeByMap(columnMap);
    }

    private void updateFailedRecord(String stationId, BasicVersion basicVersion) {
        QueryWrapper<RosterHistory> qu = new QueryWrapper<>();
        qu.eq("version", basicVersion.getVersion());
        qu.eq("ex_station_id", stationId);
        qu.eq("del_flag", 0);
        RosterHistory en = new RosterHistory();
        en.setSpare3(4);
        en.setUpdateTime(DateUtils.getNowDate());
        historyService.update(en, qu);
    }

    private void updateSuccessRecord(String stationId, BasicVersion basicVersion) {
        // 更新历史表每条记录state=3表示下发成功
        QueryWrapper<RosterHistory> qu = new QueryWrapper<>();
        qu.eq("version", basicVersion.getVersion());
        qu.eq("ex_station_id", stationId);
        qu.eq("del_flag", 0);
        RosterHistory en = new RosterHistory();
        en.setSpare3(3);
        en.setUpdateTime(DateUtils.getNowDate());
        historyService.update(en, qu);

        // 更新名单表（如果有需要）
        QueryWrapper<Roster> ro = new QueryWrapper<>();
        ro.eq("basic_id", basicVersion.getId());
        ro.eq("ex_station_id", stationId);
        Roster ent = new Roster();
        ent.setSpare3(3);
        rosterService.update(ent, ro);
    }

    @Async("taskExecutor")
    protected CompletableFuture<Void> sendPostRequestAsync(BasicVersion basicVersion, String stationId, List<RosterHistory> dataModels) {
        try {
            sendPostRequest(basicVersion, stationId, dataModels);
            return CompletableFuture.completedFuture(null);
        } catch (Exception e) {
            log.error("下发请求失败: " + e.getMessage(), e);
            updateFailedRecord(stationId, basicVersion);
            CompletableFuture<Void> failedFuture = new CompletableFuture<>();
            failedFuture.completeExceptionally(e);
            return failedFuture;
        }
    }

    /**
     * 循环下发
     *
     * @param basicVersion
     * @param stationId
     * @param dataModels
     */
//    private void sendPostRequest(BasicVersion basicVersion, String stationId, List<RosterHistory> dataModels) {
//        RestTemplate restTemplate = new RestTemplate();
//        Map<String, Object> requestBody = new HashMap<>();
//        requestBody.put("version", basicVersion.getVersion());
//        List<RosterDto> payloads = dataModels.stream().map(dm -> {
//            RosterDto dto = new RosterDto(dm.getId(), dm.getVehicleId(), dm.getVehicleType(), dm.getStartDate(), dm.getEndDate(), dm.getDiscountType(), dm.getDiscountRate(), dm.getDiscountAmount(), dm.getType(), dm.getBeginRoadNo(), dm.getEndRoadNo(), dm.getEnStationId(), dm.getEnStationHex(), dm.getExStationId(), dm.getExStationHex(), dm.getNoFreeAmount());
//            return dto;
//        }).collect(Collectors.toList());
//        requestBody.put("data", payloads);
//        String fileName = "list_00_differtollvehicle_" + DateUtils.dateTimeNow() + ".json";
//        HttpHeaders headers = new HttpHeaders();
//        headers.set("Content-Type", "application/json; charset=utf-8");
//        headers.set("Accept-Charset", "utf-8");
//        headers.add("user", "lane");
//        headers.add("pass", Md5Utils.EncryptEx("Xgssoft", true, "xgs", false));
//        headers.add("md5", Md5Utils.hash(JSON.toJSONString(requestBody)));
//        headers.add("filename", fileName);
//        HttpEntity<String> request = new HttpEntity<>(JSON.toJSONString(requestBody), headers);
//        Lane info = laneService.getById(stationId);
//        String url = info.getIp() + fileName;
//        log.info("版本号[{}]-ID[{}]-[{}]-[{}],下发json：{}", basicVersion.getVersion(), stationId, info.getStationHex(), info.getStationName(), JSON.toJSONString(requestBody));
//        try {
//            ResponseEntity<String> response = restTemplate.postForEntity(url, request, String.class);
//            JSONObject jsonResult = JSON.parseObject(response.getBody());
//            if (jsonResult.getInteger("code") != 200) {
//                log.error("版本号[{}]-ID[{}]-[{}]-[{}],下发失败：{}", basicVersion.getVersion(), stationId, info.getStationHex(), info.getStationName(), jsonResult.getString("msg"));
//                res.put("code", "fail");
//                res.put("msg", stationId + "下发结果：" + jsonResult.getString("msg"));
//
//                QueryWrapper<RosterHistory> qu = new QueryWrapper<>();
//                qu.eq("version", basicVersion.getVersion());
//                qu.eq("ex_station_id", stationId);
//                qu.eq("del_flag", 0);
//                RosterHistory en = new RosterHistory();
//                en.setSpare3(4);
//                en.setUpdateTime(DateUtils.getNowDate());
//                historyService.update(en, qu);
//            } else {
//                res.put("code", "ok");
//                BasicVersion basic = new BasicVersion();
//                basic.setId(basicVersion.getId());
//                basic.setState(2);
//                basic.setUpdateTime(DateUtils.getNowDate());
//                versionService.updateById(basic);
//
//                QueryWrapper<Roster> ro = new QueryWrapper<>();
//                ro.eq("basic_id", basicVersion.getId());
//                ro.eq("ex_station_id", stationId);
//                Roster ent = new Roster();
//                ent.setSpare3(3);
//                rosterService.update(ent, ro);
//
//                QueryWrapper<RosterHistory> qu = new QueryWrapper<>();
//                qu.eq("version", basicVersion.getVersion());
//                qu.eq("ex_station_id", stationId);
//                qu.eq("del_flag", 0);
//                RosterHistory en = new RosterHistory();
//                en.setSpare3(3);
//                en.setUpdateTime(DateUtils.getNowDate());
//                historyService.update(en, qu);
//            }
//        } catch (RuntimeException e) {
//            res.put("code", "fail");
//            res.put("msg", info.getStationName() + "下发失败：" + e.getMessage());
//        }
//    }

    private void sendPostRequest(BasicVersion basicVersion, String stationId, List<RosterHistory> dataModels) {
        RestTemplate restTemplate = new RestTemplate();
        Map<String, Object> requestBody = new HashMap<>();
        requestBody.put("version", basicVersion.getVersion());
        List<RosterDto> payloads = dataModels.stream().map(dm -> {
            RosterDto dto = new RosterDto(dm.getId(), dm.getVehicleId(), dm.getVehicleType(), dm.getStartDate(), dm.getEndDate(), dm.getDiscountType(), dm.getDiscountRate(), dm.getDiscountAmount(), dm.getType(), dm.getBeginRoadNo(), dm.getEndRoadNo(), dm.getEnStationId(), dm.getEnStationHex(), dm.getExStationId(), dm.getExStationHex(), dm.getNoFreeAmount());
            return dto;
        }).collect(Collectors.toList());
        requestBody.put("data", payloads);
        String fileName = "list_00_differtollvehicle_" + DateUtils.dateTimeNow() + ".json";
        HttpHeaders headers = new HttpHeaders();
        headers.set("Content-Type", "application/json; charset=utf-8");
        headers.set("Accept-Charset", "utf-8");
        headers.add("user", "lane");
        headers.add("pass", Md5Utils.EncryptEx("Xgssoft", true, "xgs", false));
        headers.add("md5", Md5Utils.hash(JSON.toJSONString(requestBody)));
        headers.add("filename", fileName);
        HttpEntity<String> request = new HttpEntity<>(JSON.toJSONString(requestBody), headers);
        Lane info = laneService.getById(stationId);
        String url = info.getIp() + fileName;

        log.info("版本号[{}]-ID[{}]-[{}]-[{}],下发时间：{}", basicVersion.getVersion(), stationId, info.getStationHex(), info.getStationName(), DateUtils.getTime());
        try {
            ResponseEntity<String> response = restTemplate.postForEntity(url, request, String.class);
            JSONObject jsonResult = JSON.parseObject(response.getBody());
            if (jsonResult.getInteger("code") != 200) {
                throw new RuntimeException(jsonResult.getString("msg"));
            }
            updateSuccessRecord(stationId, basicVersion);
        } catch (RuntimeException e) {
            throw e;
        }
//        try {
//            ResponseEntity<String> response = restTemplate.postForEntity(url, request, String.class);
//            JSONObject jsonResult = JSON.parseObject(response.getBody());
//            if (jsonResult.getInteger("code") != 200) {
//                log.error("版本号[{}]-ID[{}]-[{}]-[{}],下发失败：{}", basicVersion.getVersion(), stationId, info.getStationHex(), info.getStationName(), jsonResult.getString("msg"));
//                res.put("code", "fail");
//                res.put("msg", stationId + "下发结果：" + jsonResult.getString("msg"));
//
//                QueryWrapper<RosterHistory> qu = new QueryWrapper<>();
//                qu.eq("version", basicVersion.getVersion());
//                qu.eq("ex_station_id", stationId);
//                qu.eq("del_flag", 0);
//                RosterHistory en = new RosterHistory();
//                en.setSpare3(4);
//                en.setUpdateTime(DateUtils.getNowDate());
//                historyService.update(en, qu);
//            } else {
//                res.put("code", "ok");
//                BasicVersion basic = new BasicVersion();
//                basic.setId(basicVersion.getId());
//                basic.setState(2);
//                basic.setUpdateTime(DateUtils.getNowDate());
//                versionService.updateById(basic);
//
//                QueryWrapper<Roster> ro = new QueryWrapper<>();
//                ro.eq("basic_id", basicVersion.getId());
//                ro.eq("ex_station_id", stationId);
//                Roster ent = new Roster();
//                ent.setSpare3(3);
//                rosterService.update(ent, ro);
//
//                QueryWrapper<RosterHistory> qu = new QueryWrapper<>();
//                qu.eq("version", basicVersion.getVersion());
//                qu.eq("ex_station_id", stationId);
//                qu.eq("del_flag", 0);
//                RosterHistory en = new RosterHistory();
//                en.setSpare3(3);
//                en.setUpdateTime(DateUtils.getNowDate());
//                historyService.update(en, qu);
//            }
//        } catch (RuntimeException e) {
//            res.put("code", "fail");
//            res.put("msg", info.getStationName() + "下发失败：" + e.getMessage());
//        }
    }

    /**
     * 删除版本
     */
    @PreAuthorize("@ss.hasPermi('system:basic_version:remove')")
    @Log(title = "基础版本信息", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    public AjaxResult remove(@PathVariable String[] ids) {
        for (String id : ids) {
            BasicVersion version = versionService.getById(id);
            if (version.getState() != 0) {
                return AjaxResult.error(-1, "已添加数据，禁止删除");
            } else {
                QueryWrapper<Roster> query = Wrappers.query();
                query.eq("basic_id", version.getId());
                long count = rosterService.count(query);
                if (count > 0) {
                    return AjaxResult.error(-1, "已添加数据禁止删除,请先删除数据!");
                }

                if (StringUtils.isNotEmpty(version.getVersion())) {
                    QueryWrapper<RosterHistory> query1 = Wrappers.query();
                    query1.eq("version", version.getVersion());
                    query1.eq("del_flag", 0);
                    long count1 = historyService.count(query1);
                    if (count1 > 0) {
                        return AjaxResult.error(-1, version.getVersion() + "已打包数据禁止删除,请先删除数据!");
                    }
                }
            }
        }
        return toAjax(versionService.removeByIds(Arrays.asList(ids)));
    }

    /**
     * 获取交易数据
     *
     * @param fee
     */
    @PreAuthorize("@ss.hasPermi('system:basic_version:fee')")
    @GetMapping("/fee")
    public AjaxResult fee(Fee fee) {
        List<Fee> list = feeService.query(fee);
        return AjaxResult.success(list);
    }

    /**
     * 导出交易数据
     *
     * @param fee
     * @param response
     */
    @PreAuthorize("@ss.hasPermi('system:basic_version:export')")
    @PostMapping("/export")
    public void export(HttpServletResponse response, Fee fee) {
        List<Fee> list = feeService.query(fee);
        if (!list.isEmpty()) {
            for (Fee f : list) {
                f.setExvehicletype(DictUtils.getDictLabel("car_type", f.getExvehicletype()));
                f.setExitfeetype(DictUtils.getDictLabel("exit_fee_type", f.getExitfeetype()));
                f.setFeemileage(f.getFeemileage() / 1000);
//                f.setPayfee(f.getPayfee() / 100);
//                f.setDiscountfee(f.getDiscountfee() / 100);
//                f.setFee(f.getFee() / 100);
            }
            ExcelUtil<Fee> util = new ExcelUtil<Fee>(Fee.class);
            util.exportExcel(response, list, "交易数据");
        }
    }

    /**
     * 统计下发优惠数据
     *
     * @return
     */
    @PreAuthorize("@ss.hasPermi('system:basic:statistics')")
    @GetMapping("/statistics")
    public AjaxResult issuedStatistics(HttpServletRequest request, HttpServletResponse response) {
        int season = Integer.parseInt(request.getParameter("season"));
        String vehicleId = request.getParameter("vehicleId");
        int isExport = Integer.parseInt(request.getParameter("isExport"));
        String beginTime = null;
        String endTime = null;
        QueryWrapper<RosterHistory> query = Wrappers.query();
        query.eq("spare3", 3);
        query.eq("dept_id", getDeptId());
        query.eq("del_flag", 0);
        if (StringUtils.isNotEmpty(vehicleId)) {
            query.like("vehicle_id", vehicleId);
        }
        LocalDate firstDay, lastDay;
        int currentYear = LocalDate.now().getYear();
        if (1 == season) {
            firstDay = LocalDate.of(currentYear, Month.JANUARY, 1);
            lastDay = LocalDate.of(currentYear, Month.MARCH, 31);
        } else if (2 == season) {
            firstDay = LocalDate.of(currentYear, Month.APRIL, 1);
            lastDay = LocalDate.of(currentYear, Month.JUNE, 30);
        } else if (3 == season) {
            firstDay = LocalDate.of(currentYear, Month.JULY, 1);
            lastDay = LocalDate.of(currentYear, Month.SEPTEMBER, 30);
        } else {
            firstDay = LocalDate.of(currentYear, Month.OCTOBER, 1);
            lastDay = LocalDate.of(currentYear, Month.DECEMBER, 31);
        }
        beginTime = DateUtils.dateTimeNow(firstDay + " 00:00:00");
        endTime = DateUtils.dateTimeNow(lastDay + " 23:59:59");
        query.apply("end_date >= TO_TIMESTAMP({0}, 'YYYY-MM-DD HH24:MI:SS')", beginTime);
        query.apply("end_date <= TO_TIMESTAMP({0}, 'YYYY-MM-DD HH24:MI:SS')", endTime);
        List<RosterHistory> list = historyService.list(query);
        if (!list.isEmpty()) {
            // 统计每个vehicleId出现的次数
            Map<String, Long> vehicleCount = list.stream().collect(Collectors.groupingBy(RosterHistory::getVehicleId, Collectors.counting()));

            List<DiscountStatistics> listBWithAllRecords = list.stream().map(h -> {
                DiscountStatistics statistics = new DiscountStatistics();
                QueryWrapper<BasicVersion> queryWrapper = Wrappers.query();
                queryWrapper.eq("version", h.getVersion());
                BasicVersion version = versionService.getOne(queryWrapper);
                statistics.setVehicleId(h.getVehicleId());
                statistics.setStartDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, h.getStartDate()));
                statistics.setEndDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, h.getEndDate()));
                statistics.setCollectTime(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, version.getCollectTime()));
                statistics.setDiscountRate(h.getDiscountRate());
                statistics.setCount(vehicleCount.getOrDefault(h.getVehicleId(), 0L).intValue());
                return statistics;
            }).collect(Collectors.toList());

            Map<CompositeKey, DiscountStatistics> mapByVehicleId = listBWithAllRecords.stream()
                    .collect(Collectors.toMap(
                            a -> new CompositeKey(a.getVehicleId(), a.getEndDate(), a.getCollectTime(), a.getDiscountRate()),
                            a -> a,
                            (existing, replacement) -> replacement
                    ));

            // 将Map转换回List
            List<DiscountStatistics> uniqueList = new ArrayList<>(mapByVehicleId.values());
            if (isExport == 1) {
                ExcelUtil<DiscountStatistics> util = new ExcelUtil<DiscountStatistics>(DiscountStatistics.class);
                util.exportExcel(response, uniqueList, "下发统计数据导出");
            } else {
                return AjaxResult.success(uniqueList);
            }
        }
        return AjaxResult.success();
    }
}
